home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / program / misc / mkdepend.lha / MkDepend-1.0 / main.c < prev    next >
C/C++ Source or Header  |  1995-09-14  |  29KB  |  1,161 lines

  1. /*
  2. $VER: main:c 1.0 (13-Sep-95) Copyright © by Lars Düning
  3. */
  4.  
  5. /*---------------------------------------------------------------------------
  6. ** Main module of MkDepend.
  7. **
  8. ** Copyright © 1995  Lars Düning  -  All rights reserved.
  9. ** Permission granted for non-commercial use.
  10. **---------------------------------------------------------------------------
  11. ** The module implements the argument parsing and the control flow.
  12. **
  13. ** Usage:
  14. **   mkdepend {-i|INCLUDE <includepath>[::<symbol>]}
  15. **            {-x|EXCEPT  <filepattern>}
  16. **            {-s|SUFFIX  <src_ext>{,<src_ext>}[:<obj_ext>] | :<obj_ext>}
  17. **            {-p|OBJPAT  <src_ext>{,<src_ext>}:<obj_pattern>
  18. **            [-f|MAKE    <makefile>]
  19. **            [-v|VERBOSE]
  20. **            {<filepattern>}
  21. **
  22. ** The <objpattern> recognizes as meta-symbols:
  23. **   %s: the full sourcename (w/o suffix)
  24. **   %p: the path part of the sourcename
  25. **   %n: the base of the sourcename (w/o suffix)
  26. **   %x: the character x for every x != s, p or n.
  27. **
  28. **---------------------------------------------------------------------------
  29. ** C: DICE 3.01
  30. **---------------------------------------------------------------------------
  31. ** [lars] Lars Düning; Am Wendenwehr 25; D-38114-Braunschweig;
  32. **                     Germany; Tel. 49-531-345692
  33. **---------------------------------------------------------------------------
  34. ** 11-Sep-95 [lars]
  35. ** 13-Sep-95 [lars] current
  36. **---------------------------------------------------------------------------
  37. */
  38.  
  39. #include <assert.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <sys/stat.h>
  44.  
  45. #include <dos/dos.h>
  46. #include <dos/rdargs.h>
  47. #include <exec/types.h>
  48. #include <exec/libraries.h>
  49. #include <clib/exec_protos.h>
  50. #include <clib/dos_protos.h>
  51.  
  52. #include "reader.h"
  53. #include "nodes.h"
  54.  
  55. extern struct Library *SysBase;
  56.  
  57. /*-------------------------------------------------------------------------*/
  58.  
  59. /* Release version number, should match the version number in the Makefiles */
  60.  
  61. #define VERSION "1.0"
  62.  
  63. /* Dynamic string array */
  64.  
  65. typedef struct sarray
  66. {
  67.   int     size;   /* Number of used strings */
  68.   int     alloc;  /* Number of allocated string pointers */
  69.   char ** strs;   /* Array of string pointers */
  70. } SArray;
  71.  
  72. /* Program arguments */
  73.  
  74. static short    bVerbose = FALSE;          /* TRUE: Verbose action */
  75. static SArray   aFiles   = { 0, 0, NULL }; /* Source files */
  76. static SArray   aAvoid   = { 0, 0, NULL }; /* Source files to avoid */
  77. static SArray   aIncl    = { 0, 0, NULL }; /* Include paths */
  78. static SArray   aSymbol  = { 0, 0, NULL }; /* Include path symbols */
  79. static SArray   aSrcExt  = { 0, 0, NULL }; /* Source file extensions */
  80. static SArray   aObjExt  = { 0, 0, NULL }; /* Associated object file extensions */
  81. static SArray   aObjPat  = { 0, 0, NULL }; /* Associated object file patterns */
  82. static char   * sObjExt  = NULL;           /* Default object file extension */
  83. static char   * sMake    = NULL;           /* Name of the Makefile */
  84.  
  85. /* Misc Variables */
  86.  
  87. static char * aPgmName = NULL;  /* Name of the program executable */
  88. char * aVersion = "$VER: MkDepend " VERSION " (" __DATE__ ")";
  89.  
  90. static struct stat aMakeStat;    /* Stat buffer for the Makefile */
  91. static int         bMakeExists;  /* TRUE: Old Makefile exists */
  92.  
  93. static int         returncode = RETURN_OK;   /* Global return code */
  94.  
  95. /*-----------------------------------------------------------------------*/
  96. static void
  97. set_rc (int code, int bAbort)
  98.  
  99. /* Set the global returncode to <code> given that <code> is higher
  100.  * than the current one.
  101.  * If <bAbort>, exit immediately then.
  102.  */
  103.  
  104. {
  105.   if (code > returncode)
  106.     returncode = code;
  107.   if (bAbort)
  108.     exit(returncode);
  109. }
  110.  
  111. /*-----------------------------------------------------------------------*/
  112. static int
  113. chmod (char *file, long mode)
  114.  
  115. /* Set the access mode of a file.
  116.  * For Amiga-OS, only the owner access can be set.
  117.  */
  118.  
  119. {
  120.   BPTR lock;
  121.   struct FileInfoBlock *info;
  122.   int rc;
  123.  
  124.   /* Unix mode 'rwx??????' => DOS mode 'rwxw' aka 'rwxd'.
  125.   ** Well, this should be done using the FIB* constants from dos.h
  126.   ** but they will hardly change and 'knowing' them keeps this a one-liner.
  127.   ** Note that the Amiga-OS bits disallow the operation when set.
  128.   */
  129.   mode = ~((mode & 0700) >> 5 | (mode & 0200) >> 7) & 017;
  130.   info = (struct FileInfoBlock *) malloc(sizeof (struct FileInfoBlock));
  131.   if (info == NULL) return -1;
  132.   rc = -1;
  133.   if ((lock = Lock(file, SHARED_LOCK)) == NULL) goto chmod_exit;
  134.   if (Examine(lock, info) == DOSFALSE) goto chmod_exit;
  135.   UnLock(lock);
  136.   if (SetProtection(file, (info->fib_Protection & (~017)) | mode) != DOSFALSE)
  137.     rc = 0;
  138. chmod_exit:
  139.   free (info);
  140.   return rc;
  141. }
  142.  
  143. /*-----------------------------------------------------------------------*/
  144. static void
  145. CheckStacksize (LONG try_size)
  146.  
  147. /* Check the stacksize of this process against try_size.
  148.  * If the actual stacksize is smaller, print a message and exit.
  149.  */
  150.  
  151. {
  152.   struct Task *pThis;
  153.  
  154.   pThis = (struct Task *)FindTask(NULL);
  155.  
  156.   /* Sanity checks, shouldn't happen anyway */
  157.   assert(pThis && pThis->tc_Node.ln_Type == NT_PROCESS);
  158.  
  159.   if ((LONG)((char *)pThis->tc_SPUpper - (char *)pThis->tc_SPLower) < try_size)
  160.   {
  161.     printf("%s: Needs at least %ld KByte stack.\n", aPgmName, (try_size+512) >> 10);
  162.     exit(RETURN_ERROR);
  163.   }
  164. }
  165.  
  166. /*-------------------------------------------------------------------------*/
  167. static void
  168. check_os2 (void)
  169.  
  170. /* Check if OS2 is available. If not, print a message and exit.
  171.  */
  172.  
  173. {
  174.   char *sNeedsOS2 = "Fatal: Needs OS 2.0 or better.\n";
  175.  
  176.   if (SysBase->lib_Version < 36)
  177.   {
  178.     Write(Output(), sNeedsOS2, strlen(sNeedsOS2));
  179.     set_rc(RETURN_FAIL, 1);
  180.   }
  181. }
  182.  
  183. /*-------------------------------------------------------------------------*/
  184. static void
  185. exit_doserr (int code)
  186.  
  187. /* Print a message according to IoErr(), then exit with <code>.
  188.  */
  189.  
  190. {
  191.   PrintFault(IoErr(), aPgmName);
  192.   set_rc(code, 1);
  193. }
  194.  
  195. /*-------------------------------------------------------------------------*/
  196. static void
  197. exit_nomem (int code)
  198.  
  199. /* Print a "Out of Memory" message and exit with <code>.
  200.  */
  201.  
  202. {
  203.   printf("%s: Out of memory.\n", aPgmName);
  204.   set_rc(code, 1);
  205. }
  206.  
  207. /*-------------------------------------------------------------------------*/
  208. static int
  209. array_addfile (SArray *pArray, char * pName)
  210.  
  211. /* Add a copy of <*pName> to the string array <pArray>.
  212.  * Return 0 on success, non-0 on error.
  213.  * If pName is NULL, the array is simply extended by a NULL pointer.
  214.  */
  215.  
  216. {
  217.   char ** pStrs;
  218.   assert(pArray->size <= pArray->alloc);
  219.   if (pArray->size+1 > pArray->alloc)
  220.   {
  221.     pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+4));
  222.     if (!pStrs)
  223.       return 1;
  224.     pArray->strs = pStrs;
  225.     pArray->alloc += 4;
  226.   }
  227.   else
  228.     pStrs = pArray->strs;
  229.   if (pName)
  230.   {
  231.     pStrs[pArray->size] = strdup(pName);
  232.     if (!pStrs[pArray->size])
  233.       return 1;
  234.   }
  235.   else
  236.     pStrs[pArray->size] = NULL;
  237.   pArray->size++;
  238.   return 0;
  239. }
  240.  
  241. /*-------------------------------------------------------------------------*/
  242. static int
  243. array_addlist (SArray *pArray, int count, char ** pList)
  244.  
  245. /* Add the <count> string pointers from <pList> to string array <pArray>.
  246.  * pList may be freed after return, the strings themselves are still
  247.  * referenced (by pArray then).
  248.  * Return 0 on success, non-0 else.
  249.  */
  250.  
  251. {
  252.   char ** pStrs;
  253.   int     i;
  254.  
  255.   assert(pList);
  256.   if (!count)
  257.     return 0;
  258.   assert(pArray->size <= pArray->alloc);
  259.   if (pArray->size+count > pArray->alloc)
  260.   {
  261.     pStrs = (char **)realloc(pArray->strs, sizeof(char *)*(pArray->alloc+count));
  262.     if (!pStrs)
  263.       return 1;
  264.     pArray->strs = pStrs;
  265.     pArray->alloc += count;
  266.   }
  267.   else
  268.     pStrs = pArray->strs;
  269.   for (i = 0; i < count; i++)
  270.     pStrs[pArray->size++] = pList[i];
  271.   return 0;
  272. }
  273.  
  274. /*-------------------------------------------------------------------------*/
  275. static int
  276. add_expfile (SArray *pArray, char * pName)
  277.  
  278. /* Glob filename <*pName> and add the filenames to string array <pArray>.
  279.  * Return 0 on success, non-0 else.
  280.  *
  281.  * The function uses DICE' supplied function expand_args() which does not
  282.  * implement all possible wildcard patterns.
  283.  */
  284.  
  285. {
  286.   char  * argv[] = { NULL, pName, NULL };
  287.   int     argc = 2;
  288.   char ** xargv;
  289.   int     xargc;
  290.   int     rc;
  291.  
  292.   if (expand_args(argc, argv, &xargc, &xargv))
  293.   {
  294.     printf("%s: Error expanding %s\n", aPgmName, pName);
  295.     set_rc(RETURN_ERROR, 1);
  296.   }
  297.   assert(xargc > 1);
  298.  
  299.   rc = 0;
  300.   if (xargc > 1)
  301.   {
  302.     rc = array_addlist(pArray, xargc-1, xargv+1);
  303.     if (rc)
  304.     {
  305.       while (--xargc > 0)
  306.         if (xargv[xargc])
  307.           free(xargv[xargc]);
  308.     }
  309.     free(xargv);
  310.   }
  311.  
  312.   return rc;
  313. }
  314.  
  315. /*-------------------------------------------------------------------------*/
  316. static void
  317. getargs (void)
  318.  
  319. /* Get the arguments from the commandline.
  320.  * Unfortunately we have to emulate ReadArgs() as we have several /M values
  321.  * in our template.
  322.  */
  323.  
  324. {
  325.   int  i;                 /* all purpose */
  326.  
  327.   #define BUFSIZE 1024
  328.   char aBuffer[BUFSIZE];  /* Argument buffer */
  329.   char aArgBuf[BUFSIZE];  /* Source buffer for separator less arguments */
  330.   long item, arg;         /* Result from ReadItem(), FindArg() */
  331.   struct CSource aArgSrc; /* For postponed arguments */
  332.  
  333.   enum {
  334.     NoArg, QuesFound, OtherArg, QuesPending
  335.   } eHelp;
  336.   enum {
  337.     Standard, ParseMake, ParseIncl, ParseExcept, ParseSuffix, ParseObjpat
  338.   } eMulti;
  339.  
  340.   /* General command template */
  341.   char * sTemplate
  342.     = "-F=MAKE/K,-I=INCLUDE/K,-X=EXCEPT/K,-S=SUFFIX/K,-P=OBJPAT/K,-V=VERBOSE/S,FILES/M";
  343.   #define TEMP_MAKE    0
  344.   #define TEMP_INCLUDE 1
  345.   #define TEMP_EXCEPT  2
  346.   #define TEMP_SUFFIX  3
  347.   #define TEMP_PATTERN 4
  348.   #define TEMP_VERBOSE 5
  349.   #define TEMP_FILES   6
  350.  
  351.   /* Options which allow for no separator */
  352.   char * sAbbrev
  353.     = "-F/K,-I/K,-X/K,-S/K,-P/K";
  354.   #define ABBREV_MAKE    0
  355.   #define ABBREV_INCLUDE 1
  356.   #define ABBREV_EXCEPT  2
  357.   #define ABBREV_SUFFIX  3
  358.   #define ABBREV_PATTERN 4
  359.  
  360.   /* Translation table abbrev indices to template indices */
  361.   int aA2T[] = { TEMP_MAKE, TEMP_INCLUDE, TEMP_EXCEPT, TEMP_SUFFIX, TEMP_PATTERN };
  362.  
  363.   eHelp = NoArg;
  364.   eMulti = Standard;
  365.   aArgSrc.CS_Buffer = NULL;
  366.   while(1)
  367.   {
  368.     if (eHelp == QuesPending)
  369.     {
  370.       aBuffer[0] = '?';
  371.       aBuffer[1] = '\0';
  372.       item = ITEM_UNQUOTED;
  373.       eHelp = OtherArg;
  374.     }
  375.     else
  376.     {
  377.       aBuffer[0] = '\0';
  378.       item = ReadItem(aBuffer, BUFSIZE, aArgSrc.CS_Buffer ? &aArgSrc : NULL);
  379.     }
  380.  
  381.     if (ITEM_EQUAL == item)
  382.       item = ITEM_UNQUOTED;
  383.     if (ITEM_ERROR == item)
  384.       exit_doserr(RETURN_ERROR);
  385.  
  386.     if (ITEM_NOTHING == item)
  387.     {
  388.       if (!aArgSrc.CS_Buffer && eHelp != QuesFound)
  389.         break; /* outer while(1) */
  390.       if (aArgSrc.CS_Buffer)
  391.         aArgSrc.CS_Buffer = NULL;
  392.       else
  393.       {
  394.         FGetC(Input()); /* re-read newline */
  395.         Write(Output(), sTemplate, strlen(sTemplate));
  396.         Write(Output(), ": ", 2);
  397.         eHelp = NoArg;
  398.         eMulti = Standard;
  399.       }
  400.       continue;
  401.     }
  402.  
  403.     if (eHelp == NoArg && eMulti == Standard && !strcmp(aBuffer, "?"))
  404.     {
  405.       eHelp = QuesFound;
  406.       continue;
  407.     }
  408.  
  409.     /* At this point, we have an arg beside '?' so mark the '?'
  410.      * for reinsertion
  411.      */
  412.     if (eHelp == QuesFound)
  413.     {
  414.       eHelp = QuesPending;
  415.     }
  416.  
  417.     /* Check if the argument is a keyword */
  418.     arg = -1;
  419.     if (ITEM_UNQUOTED == item && !aArgSrc.CS_Buffer)
  420.     {
  421.       /* Shortcuts need no separator */
  422.       if (aBuffer[0] == '-' && aBuffer[1] != '\0' && aBuffer[2] != '\0')
  423.       {
  424.         char aTmp[3] = { '-', aBuffer[1], '\0' };
  425.         arg = FindArg(sAbbrev, aTmp);
  426.         if (arg != -1)
  427.         {
  428.           int len;
  429.           arg = aA2T[arg];
  430.           strcpy(aArgBuf, aBuffer+2);
  431.           len = strlen(aArgBuf);
  432.           aArgBuf[len] = '\n';   /* ReadItem() needs this as terminator */
  433.           aArgBuf[len+1] = '\0';
  434.           aBuffer[2] = '\0';
  435.           aArgSrc.CS_Buffer = aArgBuf;
  436.           aArgSrc.CS_Length = len+1;
  437.           aArgSrc.CS_CurChr = 0;
  438.         }
  439.       }
  440.       if (arg == -1)
  441.         arg = FindArg(sTemplate, aBuffer);
  442.     }
  443.     /* arg == -1: aBuffer is an argument
  444.      * arg != -1: bufindex == 0: aBuffer is keyword
  445.      */
  446.  
  447.     /* Evaluate keyword if any */
  448.     switch(arg)
  449.     {
  450.     case TEMP_MAKE:
  451.       eMulti = ParseMake;
  452.       break;
  453.     case TEMP_INCLUDE:
  454.       eMulti = ParseIncl;
  455.       break;
  456.     case TEMP_EXCEPT:
  457.       eMulti = ParseExcept;
  458.       break;
  459.     case TEMP_SUFFIX:
  460.       eMulti = ParseSuffix;
  461.       break;
  462.     case TEMP_PATTERN:
  463.       eMulti = ParseObjpat;
  464.       break;
  465.     case TEMP_VERBOSE:
  466.       bVerbose = 1;
  467.       break;
  468.     default:
  469.       assert(arg == -1);
  470.       break;
  471.     }
  472.  
  473.     if (arg != -1)
  474.       continue; /* of while(1) */
  475.  
  476.     /* Assign argument value (if any) */
  477.     switch (eMulti)
  478.     {
  479.     case Standard:
  480.       if (ITEM_QUOTED == item)
  481.         i = array_addfile(&aFiles, aBuffer);
  482.       else
  483.         i = add_expfile(&aFiles, aBuffer);
  484.       if (i)
  485.         exit_nomem(RETURN_FAIL);
  486.       break;
  487.  
  488.     case ParseMake:
  489.       if (sMake)
  490.         free(sMake);
  491.       sMake = strdup(aBuffer);
  492.       if (!sMake)
  493.         exit_nomem(RETURN_FAIL);
  494.       break;
  495.  
  496.     case ParseExcept:
  497.       if (ITEM_QUOTED == item)
  498.         i = array_addfile(&aAvoid, aBuffer);
  499.       else
  500.         i = add_expfile(&aAvoid, aBuffer);
  501.       if (i)
  502.         exit_nomem(RETURN_FAIL);
  503.       break;
  504.  
  505.     case ParseIncl:
  506.       {
  507.         char * pSym, * pMark;
  508.  
  509.         /* Allow for <path>::<symbol> notation */
  510.         pSym = NULL;
  511.         pMark = aBuffer+strlen(aBuffer);
  512.         if (pMark != aBuffer)
  513.         {
  514.           pMark--;
  515.           while (!pSym && pMark >= aBuffer+1)
  516.           {
  517.             if (':' != *pMark)
  518.             {
  519.               pMark--;
  520.               continue;
  521.             }
  522.             if (':' != *(pMark-1))
  523.             {
  524.               pMark -= 2;
  525.               continue;
  526.             }
  527.             pSym = pMark+1;
  528.             *(pMark-1) = '\0';
  529.           }
  530.         }
  531.         if (pSym && !strlen(pSym))
  532.           pSym = NULL;
  533.         i = array_addfile(&aSymbol, pSym);
  534.         if (i)
  535.           exit_nomem(RETURN_FAIL);
  536.  
  537.         /* Make sure <path> ends in a ':' or '/' */
  538.         pMark = aBuffer+strlen(aBuffer);
  539.         if (pMark > aBuffer && ':' != *(pMark-1) && '/' != *(pMark-1))
  540.         {
  541.           *pMark = '/';
  542.           *(pMark+1) = '\0';
  543.         }
  544.         i = array_addfile(&aIncl, aBuffer);
  545.         if (i)
  546.           exit_nomem(RETURN_FAIL);
  547.       }
  548.       break;
  549.  
  550.     case ParseSuffix:
  551.     case ParseObjpat:
  552.       {
  553.         char * pMark, *pOsfix;
  554.  
  555.         /* Allow for <src_suffix>:<obj_suffix> notation */
  556.         pOsfix = NULL;
  557.         pMark = aBuffer+strlen(aBuffer);
  558.         if (pMark != aBuffer)
  559.         {
  560.           pMark--;
  561.           while (!pOsfix && pMark >= aBuffer)
  562.           {
  563.             if (':' != *pMark)
  564.             {
  565.               pMark--;
  566.               continue;
  567.             }
  568.             pOsfix = pMark+1;
  569.             *pMark = '\0';
  570.           }
  571.         }
  572.         if (pOsfix && !strlen(pOsfix))
  573.           pOsfix = NULL;
  574.  
  575.         if (ParseObjpat == eMulti && !pOsfix)
  576.         {
  577.           printf("%s: Object pattern missing in argument.\n", aPgmName);
  578.           set_rc(RETURN_WARN, 0);
  579.           break;
  580.         }
  581.  
  582.         /* :<obj_suffix> alone defines default object suffix */
  583.         if (pOsfix && !strlen(aBuffer))
  584.         {
  585.           if (sObjExt)
  586.             free(sObjExt);
  587.           sObjExt = strdup(pOsfix);
  588.           if (!sObjExt)
  589.             exit_nomem(RETURN_FAIL);
  590.         }
  591.         else
  592.         {
  593.           char * pSfix;
  594.  
  595.           /* Allow for <sfix1>,<sfix2>,...,<sfixn> for source suffixes */
  596.           for ( pSfix = aBuffer
  597.               ; pMark = strchr(pSfix, ',')
  598.               ; pSfix = pMark+1
  599.               )
  600.           {
  601.             *pMark = '\0';
  602.             if (strlen(pSfix))
  603.             {
  604.               if (   array_addfile(&aSrcExt, pSfix)
  605.                   || (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
  606.                                             : array_addfile(&aObjPat, pOsfix)
  607.                      )
  608.                  )
  609.                 exit_nomem(RETURN_FAIL);
  610.             }
  611.           }
  612.           if (strlen(pSfix))
  613.           {
  614.             if (   array_addfile(&aSrcExt, pSfix)
  615.                 || (ParseSuffix == eMulti ? array_addfile(&aObjExt, pOsfix)
  616.                                           : array_addfile(&aObjPat, pOsfix)
  617.                    )
  618.                )
  619.               exit_nomem(RETURN_FAIL);
  620.           }
  621.         }
  622.       }
  623.       break;
  624.  
  625.     default:
  626.       assert(0);
  627.     }
  628.  
  629.     eMulti = Standard;
  630.   } /* while(1) */
  631.  
  632.   #undef BUFSIZE
  633.   #undef TEMP_MAKE
  634.   #undef TEMP_INCLUDE
  635.   #undef TEMP_EXCEPT
  636.   #undef TEMP_SUFFIX
  637.   #undef TEMP_PATTERN
  638.   #undef TEMP_VERBOSE
  639.   #undef TEMP_FILES
  640.   #undef ABBREV_MAKE
  641.   #undef ABBREV_INCLUDE
  642.   #undef ABBREV_EXCEPT
  643.   #undef ABBREV_SUFFIX
  644.   #undef ABBREV_PATTERN
  645. }
  646.  
  647. /*-------------------------------------------------------------------------*/
  648. static int
  649. readfiles (void)
  650.  
  651. /* Read and analyse all files.
  652.  * If a file can't be read, print a message.
  653.  * Return 0 if all went well, RETURN_WARN if one of the files could not be
  654.  * found, RETURN_ERROR if one of the files could not be read properly.
  655.  */
  656.  
  657. {
  658.   int           rc;       /* Return value */
  659.   struct stat   aStat;    /* buffer for stat() */
  660.   Node        * pNode;    /* Node of the file under examination */
  661.   int           srcRead;  /* Number of source files read */
  662.   int           index;    /* index in the aIncl array */
  663.   char          aName[FILENAME_MAX+1];
  664.   int           i;
  665.   const char  * pName;    /* Includefile name returned by reader */
  666.  
  667.   rc = 0;
  668.   srcRead = 0;
  669.   aName[FILENAME_MAX] = '\0';
  670.  
  671.   while (pNode = nodes_todo())
  672.   {
  673.     /* Search the correct directory to read from */
  674.     index = -1;
  675.     pNode->iInclude = 0;
  676.     strcpy(aName, pNode->pName);
  677.     i = stat(aName, &aStat);
  678.     if (i && !(pNode->flags & NODE_SOURCE))
  679.     {
  680.       for (index = 0; i && index < aIncl.size; index++)
  681.       {
  682.         strcpy(aName, aIncl.strs[index]);
  683.         strcat(aName, pNode->pName);
  684.         assert(aName[FILENAME_MAX] == '\0');
  685.         i = stat(aName, &aStat);
  686.       }
  687.       if (!i)
  688.         pNode->iInclude = index;
  689.     }
  690.     if (i || !reader_open(aName))
  691.     {
  692.       if (!i)
  693.         perror("mkdepend");
  694.       if (rc < RETURN_ERROR)
  695.         rc = RETURN_WARN;
  696.       printf("%s: Warning: Cant't read '%s'.\n", aPgmName, aName);
  697.       continue;
  698.     }
  699.     if (bVerbose)
  700.     {
  701.       printf(" reading %-65s\r", aName); fflush(stdout);
  702.     }
  703.     while (pName = reader_get())
  704.     {
  705.       if (nodes_depend(pNode, pName))
  706.       {
  707.         if (bVerbose)
  708.           printf("%+-78s\r", "");
  709.         reader_close();
  710.         exit_nomem(RETURN_FAIL);
  711.       }
  712.     }
  713.     if (bVerbose)
  714.       printf("%+-78s\r", "");
  715.     if (!reader_eof() || reader_close())
  716.     {
  717.       perror("mkdepend");
  718.       printf("%s: Error reading '%s'\n", aPgmName, aName);
  719.       rc = RETURN_ERROR;
  720.     }
  721.     else if (pNode->flags & NODE_SOURCE)
  722.     {
  723.       srcRead++;
  724.     }
  725.   } /* while (nodes_todo()) */
  726.   if (!srcRead)
  727.   {
  728.     printf("%s: No source file read.\n", aPgmName);
  729.     rc = RETURN_ERROR;
  730.   }
  731.   if (bVerbose)
  732.     fflush(stdout);
  733.   return rc;
  734. }
  735.  
  736. /*-------------------------------------------------------------------------*/
  737. static void
  738. make_objname ( char *pBuf, const char *pName, int slen
  739.              , const char * pObjExt, const char *pObjPat
  740.              )
  741.  
  742. /* Construct the name of the dependency target.
  743.  *
  744.  *   pBuf   : Buffer to construct the name in.
  745.  *   pName  : Name of the sourcefile.
  746.  *   slen   : Length of the sourcefile suffix.
  747.  *   pObjExt: Object extensions for this sourcefile, may be NULL.
  748.  *   pObjPat: Object pattern for this sourcefile, may be NULL.
  749.  *
  750.  * If pObjPat is not NULL, the pattern is used to construct the name.
  751.  * If pObjPat is NULL, the pObjExt string is appended to the sourcefile
  752.  * name (minus its source suffix) to construct the name. If pObjExt is
  753.  * NULL, the default object extension is used.
  754.  */
  755.  
  756. {
  757.   int nlen, plen;
  758.   char * pBasename;
  759.   char * pSrc, *pDst, ch;
  760.  
  761.   nlen = strlen(pName)-slen;
  762.   if (!pObjPat)
  763.   {
  764.     strcpy(pBuf, pName);
  765.     if (pObjExt)
  766.       strcpy(pBuf+nlen, pObjExt);
  767.     else
  768.       strcpy(pBuf+nlen, sObjExt);
  769.     return;
  770.   }
  771.   pBasename = FilePart(pName);
  772.   plen = pBasename-pName;
  773.   pSrc = pObjPat;
  774.   pDst = pBuf;
  775.   while ('\0' != (ch = *pSrc++))
  776.   {
  777.     if (ch != '%')
  778.     {
  779.       *pDst++ = ch;
  780.       continue;
  781.     }
  782.     ch = *pSrc++;
  783.     switch(ch)
  784.     {
  785.     case 's':
  786.       strncpy(pDst, pName, nlen);
  787.       pDst += nlen;
  788.       break;
  789.  
  790.     case 'p':
  791.       if (pName != pBasename)
  792.       {
  793.         strncpy(pDst, pName, plen);
  794.         pDst += plen;
  795.       }
  796.       break;
  797.  
  798.     case 'n':
  799.       strncpy(pDst, pBasename, nlen-plen);
  800.       pDst += nlen-plen;
  801.       break;
  802.  
  803.     case '%':
  804.       *pDst++ = '%';
  805.       break;
  806.  
  807.     default:
  808.       pSrc--; /* to read it again */
  809.       break;
  810.     }
  811.   }
  812.   *pDst = '\0';
  813. }
  814.  
  815. /*-------------------------------------------------------------------------*/
  816. static int
  817. output (void)
  818.  
  819. /* Output the collected dependencies into the Makefile.
  820.  * Return 0 on success, RETURN_WARN on a mild error, RETURN_ERROR on a
  821.  * severe error.
  822.  */
  823.  
  824. {
  825.   int       rc;
  826.   char    * pBackup;  /* Name of the Makefilebackup */
  827.   Node    * pNode;
  828.  
  829.   pBackup = NULL;
  830.  
  831.   /* Rename old Makefile if necessary */
  832.   if (bMakeExists)
  833.   {
  834.     pBackup = (char *)malloc(strlen(sMake)+4);
  835.     strcpy(pBackup, sMake);
  836.     strcat(pBackup, ".bak");
  837.     remove(pBackup);
  838.     if (rename(sMake, pBackup))
  839.     {
  840.       perror("mkdepend");
  841.       printf("%s: Can't rename '%s' to '%s'.\n", aPgmName, sMake, pBackup);
  842.       free(pBackup);
  843.       return RETURN_ERROR;
  844.     }
  845.   }
  846.  
  847.   rc = RETURN_OK;
  848.   do
  849.   {
  850.     /* Open files */
  851.     if (reader_openrw(pBackup, sMake))
  852.     {
  853.       perror("mkdepend");
  854.       printf("%s: Can't write '%s'\n", aPgmName, sMake);
  855.       rc = RETURN_ERROR;
  856.       break;
  857.     }
  858.  
  859.     if (bVerbose)
  860.     {
  861.       printf(" %s '%s'\r", bMakeExists ? "updating" : "creating", sMake); fflush(stdout);
  862.     }
  863.  
  864.     /* Copy the Makefile up to the tagline */
  865.     if (reader_copymake("# --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS FOLLOW ---\n"))
  866.     {
  867.       int i = errno;
  868.       if (bVerbose)
  869.         printf("%+-78s\r", "");
  870.       errno = i;
  871.       perror("mkdepend");
  872.       printf("%s: Error copying '%s' to '%s'.\n", aPgmName, pBackup, sMake);
  873.       rc = RETURN_ERROR;
  874.       break;
  875.     }
  876.  
  877.     /* Walk and output the dependencies */
  878.     nodes_initwalk();
  879.     while (rc != RETURN_ERROR && (pNode = nodes_inorder()))
  880.     {
  881.       if ((pNode->flags & (NODE_SOURCE|NODE_AVOID)) == NODE_SOURCE)
  882.       {
  883.         Node    * pRNode;
  884.         NodeRef * pList, * pRef;
  885.         int       suffix;         /* Suffix index */
  886.         int       slen;           /* Linelen so far */
  887.         int       len;
  888.         char      aObjname[FILENAME_MAX+1];
  889.  
  890.         aObjname[FILENAME_MAX] = '\0';
  891.  
  892.         pList = nodes_deplist(pNode);
  893.         assert(pList);
  894.         pRef = pList;
  895.  
  896.         /* Check for a given suffix.
  897.          * Search backwards in case later definitions overwrote
  898.          * earlier ones.
  899.          */
  900.         slen = strlen(pNode->pName);
  901.         for (suffix = aSrcExt.size-1; suffix >= 0; suffix--)
  902.         {
  903.           len = strlen(aSrcExt.strs[suffix]);
  904.           if (!strcmp(pNode->pName+slen-len, aSrcExt.strs[suffix]))
  905.             break;
  906.         }
  907.  
  908.         /* Construct the name of the dependency target and write it */
  909.         if (suffix >= 0)
  910.         {
  911.           make_objname( aObjname, pNode->pName, len
  912.                       , aObjExt.size ? aObjExt.strs[suffix] : NULL
  913.                       , aObjPat.size ? aObjPat.strs[suffix] : NULL
  914.                       );
  915.           assert(aObjname[FILENAME_MAX] == '\0');
  916.           if (reader_write(aObjname))
  917.           {
  918.             rc = RETURN_ERROR;
  919.             break; /* outer while */
  920.           }
  921.           slen = strlen(aObjname);
  922.         }
  923.         else
  924.         {
  925.           if (reader_write(pNode->pName))
  926.           {
  927.             rc = RETURN_ERROR;
  928.             break; /* outer while */
  929.           }
  930.           pRef = pRef->pNext;
  931.         }
  932.  
  933.         if (reader_write(" : "))
  934.         {
  935.           rc = RETURN_ERROR;
  936.           break; /* outer while */
  937.         }
  938.         slen += 3;
  939.  
  940.         for ( ; rc != RETURN_ERROR && pRef; pRef = pRef->pNext)
  941.         {
  942.           pRNode = pRef->pNode;
  943.           /* Construct the name of the dependee */
  944.           aObjname[0] = ' ';
  945.           aObjname[1] = '\0';
  946.           if (pRNode->iInclude)
  947.           {
  948.             if (aSymbol.strs[pRNode->iInclude-1])
  949.               strcat(aObjname, aSymbol.strs[pRNode->iInclude-1]);
  950.             else
  951.               strcat(aObjname, aIncl.strs[pRNode->iInclude-1]);
  952.             strcat(aObjname, pRNode->pName);
  953.           }
  954.           else
  955.           {
  956.             strcat(aObjname, pRNode->pName);
  957.           }
  958.           assert(aObjname[FILENAME_MAX] == '\0');
  959.           len = strlen(aObjname);
  960.  
  961.           /* Fit it into the line */
  962.           if (slen > 0)
  963.           {
  964.             if (slen+len > 75)
  965.             {
  966.               if (reader_writen(" \\\n", 3))
  967.               {
  968.                 rc = RETURN_ERROR;
  969.                 break; /* inner while */
  970.               }
  971.               slen = 0;
  972.             }
  973.           }
  974.           if (!slen)
  975.           {
  976.             if (reader_writen("   ", 3))
  977.             {
  978.               rc = RETURN_ERROR;
  979.               break; /* inner while */
  980.             }
  981.             slen = 3;
  982.           }
  983.           if (reader_writen(aObjname, len))
  984.           {
  985.             rc = RETURN_ERROR;
  986.             break; /* inner while */
  987.           }
  988.           slen += len;
  989.         } /* for () */
  990.         nodes_freelist(pList);
  991.         if (slen && reader_writen("\n\n", 2))
  992.         {
  993.           rc = RETURN_ERROR;
  994.           break; /* outer while */
  995.         }
  996.       } /* if (source node) */
  997.     }  /* while (treewalk */
  998.  
  999.     if (rc == RETURN_ERROR)
  1000.     {
  1001.       int i = errno;
  1002.       if (bVerbose)
  1003.         printf("%+-78s\r", "");
  1004.       errno = i;
  1005.       perror("mkdepend");
  1006.       printf("%s: Error writing '%s'.\n", aPgmName, sMake);
  1007.       rc = RETURN_ERROR;
  1008.       break;
  1009.     }
  1010.  
  1011.     /* Finish up */
  1012.     if (bVerbose)
  1013.       printf("%+-78s\r", "");
  1014.  
  1015.     if (reader_writeflush() || reader_close())
  1016.     {
  1017.       perror("mkdepend");
  1018.       printf("%s: Error writing '%s'.\n", aPgmName, sMake);
  1019.       rc = RETURN_ERROR;
  1020.       break;
  1021.     }
  1022.  
  1023.     if (bMakeExists && chmod(sMake, aMakeStat.st_mode))
  1024.     {
  1025.       /* perror("mkdepend"); */
  1026.       printf("%s: Warning: Can't update mode of '%s'.\n", aPgmName, sMake);
  1027.       rc = RETURN_WARN;
  1028.     }
  1029.  
  1030.     if (pBackup && remove(pBackup))
  1031.     {
  1032.       perror("mkdepend");
  1033.       printf("%s: Warning: Can't remove backup '%s'.\n", aPgmName, pBackup);
  1034.       rc = RETURN_WARN;
  1035.       break;
  1036.     }
  1037.  
  1038.   } while(0);
  1039.  
  1040.   /* Error cleanup */
  1041.   if (rc == RETURN_ERROR)
  1042.   {
  1043.     reader_close();
  1044.     remove(sMake);
  1045.     if (pBackup && rename(pBackup, sMake))
  1046.     {
  1047.       perror("mkdepend");
  1048.       printf("%s: Can't restore '%s' from backup '%s'\n", aPgmName, sMake, pBackup);
  1049.     }
  1050.   }
  1051.  
  1052.   if (bVerbose && rc != RETURN_ERROR)
  1053.     printf("%+-78s\r", "");
  1054.  
  1055.   if (pBackup)
  1056.     free(pBackup);
  1057.  
  1058.   return rc;
  1059. }
  1060.  
  1061. /*-------------------------------------------------------------------------*/
  1062. int main (int argc, char *argv[])
  1063.  
  1064. {
  1065.   int i;
  1066.  
  1067.   check_os2();
  1068.  
  1069.   /* Determine the program executables name */
  1070.   aPgmName = strdup(FilePart(argv[0]));
  1071.   if (!aPgmName)
  1072.     aPgmName = "mkdepend";
  1073.  
  1074.   CheckStacksize(10240);
  1075.  
  1076.   reader_init();
  1077.  
  1078.   /* Get arguments, set up defaults */
  1079.   getargs();
  1080.   if (!aFiles.size)
  1081.   {
  1082.     if (add_expfile(&aFiles, "#?.c"))
  1083.       exit_nomem(RETURN_FAIL);
  1084.   }
  1085.   if (!sObjExt)
  1086.     sObjExt = ".o";
  1087.  
  1088.   if (!aSrcExt.size)
  1089.   {
  1090.     if (array_addfile(&aSrcExt, ".c") || array_addfile(&aObjExt, NULL))
  1091.       exit_nomem(RETURN_FAIL);
  1092.   }
  1093.  
  1094.   if (bVerbose)
  1095.   {
  1096.     printf("MkDepend %s (%s) -- Make Dependency Generator\n", VERSION, __DATE__);
  1097.     puts("Copyright © 1995 Lars Düning.");
  1098.     putchar('\n');
  1099.   }
  1100.  
  1101.   /* Look for the Makefile to modify */
  1102.   if (sMake)
  1103.   {
  1104.     bMakeExists = !stat(sMake, &aMakeStat);
  1105.   }
  1106.   else
  1107.   {
  1108.     sMake = "Makefile";
  1109.     bMakeExists = !stat(sMake, &aMakeStat);
  1110.     if (!bMakeExists)
  1111.     {
  1112.       sMake = "Makefile.mk";
  1113.       bMakeExists = !stat(sMake, &aMakeStat);
  1114.     }
  1115.     if (!bMakeExists)
  1116.     {
  1117.       sMake = "DMakefile";
  1118.       bMakeExists = !stat(sMake, &aMakeStat);
  1119.     }
  1120.     if (!bMakeExists)
  1121.     {
  1122.       sMake = "SMakefile";
  1123.       bMakeExists = !stat(sMake, &aMakeStat);
  1124.     }
  1125.     if (!bMakeExists)
  1126.       sMake = "Makefile";
  1127.   }
  1128.  
  1129.   /* Add the source files to the tree */
  1130.   if (!aFiles.size)
  1131.   {
  1132.     printf("%s: No files given.\n", aPgmName);
  1133.     set_rc(RETURN_WARN, 1);
  1134.   }
  1135.   for (i = 0; i < aFiles.size; i++)
  1136.   {
  1137.     if (nodes_addsource(aFiles.strs[i], 0))
  1138.       exit_nomem(RETURN_FAIL);
  1139.   }
  1140.  
  1141.   /* Mark the exceptional files */
  1142.   for (i = 0; i < aAvoid.size; i++)
  1143.   {
  1144.     if (nodes_addsource(aAvoid.strs[i], 1))
  1145.       exit_nomem(RETURN_FAIL);
  1146.   }
  1147.  
  1148.   /* Read and analyse all those files */
  1149.   set_rc(readfiles(), 0);
  1150.  
  1151.   if (returncode < RETURN_ERROR)
  1152.     set_rc(output(), 0);
  1153.  
  1154.   if (returncode < RETURN_ERROR && bVerbose)
  1155.     printf("%s '%s'.\n", bMakeExists ? "Updated" : "Created", sMake);
  1156.  
  1157.   return returncode;
  1158. }
  1159.  
  1160. /***************************************************************************/
  1161.